package com.south.base.test.arithmetic;

import org.junit.Assert;
import org.junit.Test;

/**
 * @author Administrator
 * @date 2020/8/21 15:43
 */
public class BitOperate {
    /**
     * 插入。
     * 给定两个32位的整数N与M，以及表示比特位置的i与j。
     * 编写一种方法，将M插入N，使得M从N的第j位开始，到第i位结束。
     * 假定从j位到i位足以容纳M，也即若M = 10 011，那么j和i之间至少可容纳5个位。
     * 例如，不可能出现j = 3和i = 2的情况，因为第3位和第2位之间放不下M。
     */
    @Test
    public void insertBits() {
        Assert.assertEquals(1100, insertBits(1024, 19, 2, 6));
        Assert.assertEquals(31, insertBits(0, 31, 0, 4));
    }

    public int insertBits(int N, int M, int i, int j) {
        // 将M向右位移i位（M000）
        return (M << i) |
                // 将N的中间i到j的位置设置成0
                (N &
                        // 将中间i到j的位置设置成0（i=1,j=4即为11111111111111111111111111110001）
                        ~((-1 >>> (31 - j)) & (-1 << i)));
    }

    /**
     * 翻转数位
     * 给定一个32位整数 num，你可以将一个数位从0变为1。
     * 请编写一个程序，找出你能够获得的最长的一串1的长度。
     */
    @Test
    public void reverseBits() {
        Assert.assertEquals(8, reverseBits(1775));
        Assert.assertEquals(4, reverseBits(7));
        Assert.assertEquals(4, reverseBits(0b1100111));
        Assert.assertEquals(32, reverseBits(2147483647));
    }

    public int reverseBits(int num) {
        //先转化为字符数组
        char[] arr = Integer.toBinaryString(num).toCharArray();
        //要多余存放ints[0]=-1;ints[k]=arr.length;所以+2
        int[] ints = new int[arr.length + 2];
        ints[0] = -1;
        int k = 1;
        //0--arr.length之间存放arr中0的下标
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == '0') {
                ints[k++] = i;
            }
        }
        ints[k] = arr.length;
        if (k == 1) {
            //如果num的二进制表示全为1，直接返回arr.length+1,相当于直接将前面的0变为1
            return ints[1] + 1;
        }
        int max = 0;
        for (int i = 1; i < k; i++) {
            //这一步是核心，举个例子带进去就理解了
            int cur = ints[i + 1] - ints[i - 1] - 1;
            max = Math.max(cur, max);
        }
        return max;
    }

}
